class Player extends GameObject {
    constructor(playground, x, y, radius, color, speed, role, username, photo) {

        super()
        this.playground = playground
        this.ctx = this.playground.game_map.ctx
        this.x = x
        this.y = y
        this.vx = 0
        this.vy = 0
        this.damage_x = 0
        this.damage_y = 0
        this.damage_speed = 0
        this.move_length = 0
        this.radius = radius
        this.color = color
        this.speed = speed
        this.role = role
        this.username = username
        this.photo = photo
        this.eps = 0.01
        this.cur_skill = null
        this.spent_time = 0
        this.fireballs = []
        if (this.role !== "robot") {
            this.img = new Image();
            this.img.src = this.photo;
        }

        if (this.role === 'me') {
            this.fireball_coldtime = 3  //冷却时间
            this.fireball_img = new Image()
            this.fireball_img.src = 'https://cdn.acwing.com/media/article/image/2021/12/02/1_9340c86053-fireball.png'
            
            this.blink_coldtime = 5
            this.blink_img = new Image()
            this.blink_img.src = 'https://cdn.acwing.com/media/article/image/2021/12/02/1_daccabdc53-blink.png'
        }

        this.friction = 0.9
    }

    start() {
        this.playground.player_count ++
        this.playground.notice_board.write('已就绪：' + this.playground.player_count + '人')

        if (this.playground.player_count >= 2) {
            this.playground.state = 'fighting'
            this.playground.notice_board.write('Fighting')
        }

        if(this.role === "me") {
            this.add_listening_events()
        } else if(this.role === "robot") {
            let tx = Math.random() * this.playground.width / this.playground.scale
            let ty = Math.random() * this.playground.height / this.playground.scale
            this.move_to(tx, ty)
        }
    }

    add_listening_events() {
        let out = this
        this.playground.game_map.$canvas.on("contextmenu", function() {
            return false
        })

        this.playground.game_map.$canvas.mousedown(function(e) {
            if (out.playground.state !== 'fighting')
                return true

            const rect = out.ctx.canvas.getBoundingClientRect()

            if(e.which === 3) {
                let tx = (e.clientX - rect.left) / out.playground.scale
                let ty = (e.clientY - rect.top) / out.playground.scale
                out.move_to(tx, ty)
                if(out.playground.mode === 'multi mode') {
                    out.playground.mps.send_move_to(tx,ty)
                }
            } else if(e.which === 1) {
                let tx = (e.clientX - rect.left) / out.playground.scale
                let ty = (e.clientY- rect.top) / out.playground.scale
                if(out.cur_skill === "fireball") {
                    if(out.fireball_coldtime > out.eps)
                        return false

                    let fireball = out.shoot_fireball(tx, ty)

                    if(out.playground.mode === 'multi mode') 
                        out.playground.mps.send_shoot_fireball(tx, ty, fireball.uuid)
                }else if (out.cur_skill === 'blink') {
                    if(out.blink_coldtime > out.eps)
                        return false

                    out.blink(tx, ty)

                    if(out.playground.mode === 'multi mode') {
                        out.playground.mps.send_blink(tx, ty)
                    }
                }

                out.cur_skill = null
            }
        })

        this.playground.game_map.$canvas.keydown(function(e) {
            if (e.which === 13) { // enter
                out.playground.chat_field.show_input()
                return false
            }else if(e.which === 27) { // esc
                out.playground.chat_field.hide_input()
                return false
            }

            if (out.playground.state !== 'fighting')
                return true

            if(e.which ===  81) { // q
                if (out.fireball_coldtime > out.eps) {
                    return true
                }

                out.cur_skill = "fireball"
                return false
            } else if(e.which === 70) { // f
                if (out.blink_coldtime > out.eps) 
                    return true

                out.cur_skill = "blink"
                return false
            }
        })
    }

    blink(tx, ty) {
        let d = this.get_dist(this.x, this.y, tx, ty)
        d = Math.min(0.8, d)
        let angle = Math.atan2(ty - this.y, tx - this.x)
        this.x += d * Math.cos(angle)
        this.y += d * Math.sin(angle)

        this.blink_coldtime = 5
        this.move_length = 0  //闪现后停止移动
    }

    shoot_fireball(tx, ty) {
        let x = this.x, y = this.y
        let radius = 0.01
        let angle = Math.atan2(ty - this.y, tx - this.x)
        let vx = Math.cos(angle), vy = Math.sin(angle)
        let color = "red"
        let speed = 0.5
        let move_length = 1
        let fireball = new FireBall(this.playground, this, x, y, radius, vx, vy, color, speed, move_length, 0.01)
        this.fireballs.push(fireball)

        this.fireball_coldtime = 3

        return fireball
    }

    destroy_fireball(uuid) {
        for(let i = 0; i < this.fireballs.length; i++) {
            let fireball = this.fireballs[i]
            if (fireball.uuid === uuid) {
                fireball.destroy()
                break
            }
        }
    }

    get_dist(x1, y1, x2, y2) {
        let dx = x1 - x2
        let dy = y1 - y2
        return Math.sqrt(dx * dx + dy * dy)
    }

    move_to(tx, ty) {
        this.move_length = this.get_dist(this.x, this.y, tx, ty)
        let angle = Math.atan2(ty - this.y, tx - this.x)
        this.vx = Math.cos(angle)
        this.vy = Math.sin(angle)
    }

    is_attacked(angle, damage) {
        for (let i = 0; i < 20 + Math.random() * 10; i ++ ) {
            let x = this.x, y = this.y
            let radius = this.radius * Math.random() * 0.1
            let angle = Math.PI * 2 * Math.random()
            let vx = Math.cos(angle), vy = Math.sin(angle)
            let color = this.color
            let speed = this.speed * 10
            let move_length = this.radius * Math.random() * 5
            new Particle(this.playground, x, y, radius, vx, vy, color, speed, move_length)
        }

        this.radius -= damage
        if(this.radius < this.eps) {
            this.destroy()
            return false
        }
        this.damage_x = Math.cos(angle)
        this.damage_y = Math.sin(angle)
        this.damage_speed = damage * 50
        this.speed *= 1.5
    }

    receive_attacked(x, y, angle, damage, ball_uuid, attacker) {
        attacker.destroy_fireball(ball_uuid)
        this.x = x
        this.y = y
        this.is_attacked(angle, damage)
    }

    update() {
        this.spent_time += this.timedelta / 1000
        if (this.role === 'me' && this.playground.state === 'fighting')
            this.update_coldtime()

        this.update_move()
        this.render()
    }

    update_coldtime() {
        this.fireball_coldtime -= this.timedelta / 1000
        this.fireball_coldtime = Math.max(0, this.fireball_coldtime)

        this.blink_coldtime -= this.timedelta / 1000
        this.blink_coldtime = Math.max(0, this.blink_coldtime)
    }

    update_move() {
        if (this.role === "robot" && this.spent_time > 4 && Math.random() < 1 / 150.0) {  //人机随机射击
            let player = this.playground.players[Math.floor(Math.random() * this.playground.players.length)];
            let tx = player.x + player.speed * this.vx * this.timedelta / 1000 * 0.3;
            let ty = player.y + player.speed * this.vy * this.timedelta / 1000 * 0.3;
            this.shoot_fireball(tx, ty);
        }

        if(this.damage_speed > this.eps) {
            this.vx = this.vy = 0
            this.move_length = 0
            this.x += this.damage_x * this.damage_speed * this.timedelta / 1000
            this.y += this.damage_y * this.damage_speed * this.timedelta / 1000
            this.damage_speed *= this.friction
        } else {
            if(this.move_length < this.eps) {
                this.move_length = 0
                this.vx = this.vy = 0
                if(this.role === "robot") {
                    let tx = Math.random() * this.playground.width / this.playground.scale
                    let ty = Math.random() * this.playground.height / this.playground.scale
                    this.move_to(tx, ty)
                }
            } else {
                let moved = Math.min(this.move_length, this.speed * this.timedelta / 1000)
                this.x += this.vx * moved
                this.y += this.vy * moved
                this.move_length -= moved
            }
        }
    }

    render() {
        let scale = this.playground.scale
        if(this.role !== "robot") {
            this.ctx.save();
            this.ctx.beginPath();
            this.ctx.arc(this.x * scale, this.y * scale, this.radius * scale, 0, Math.PI * 2, false);
            this.ctx.stroke();
            this.ctx.clip();
            this.ctx.drawImage(this.img, (this.x - this.radius) * scale, (this.y - this.radius) * scale, this.radius * 2 * scale, this.radius * 2 * scale); 
            this.ctx.restore();
        }
        else {
            this.ctx.beginPath()
            this.ctx.arc(this.x * scale, this.y * scale, this.radius * scale, 0, Math.PI * 2, false)
            this.ctx.fillStyle = this.color
            this.ctx.fill()
        }

        if(this.role === 'me' && this.playground.state === 'fighting') {
            this.render_skill_coldtime()
        }
    }

    render_skill_coldtime() {
        let x = 1.5, y = 0.9, r = 0.04
        let scale = this.playground.scale
        this.ctx.save();
        this.ctx.beginPath();
        this.ctx.arc(x * scale, y * scale, r * scale, 0, Math.PI * 2, false);
        this.ctx.stroke();
        this.ctx.clip();
        this.ctx.drawImage(this.fireball_img, (x - r) * scale, (y - r) * scale, r * 2 * scale, r * 2 * scale); 
        this.ctx.restore()
        if(this.fireball_coldtime !== 0) {
            this.ctx.beginPath()
            this.ctx.moveTo(x * scale, y * scale)
            this.ctx.arc(x * scale, y * scale, r * scale, 0 - Math.PI / 2, Math.PI * 2 * (1 - this.fireball_coldtime / 3) - Math.PI / 2, false)
            this.ctx.lineTo(x * scale, y * scale)

            this.ctx.fillStyle = 'rgba(0,0,255,0.6)'
            this.ctx.fill()
        }

        x = 1.62, y = 0.9, r = 0.04
        this.ctx.save();
        this.ctx.beginPath();
        this.ctx.arc(x * scale, y * scale, r * scale, 0, Math.PI * 2, false);
        this.ctx.stroke();
        this.ctx.clip();
        this.ctx.drawImage(this.blink_img, (x - r) * scale, (y - r) * scale, r * 2 * scale, r * 2 * scale);
        this.ctx.restore()
        if(this.blink_coldtime !== 0) {
            this.ctx.beginPath()
            this.ctx.moveTo(x * scale, y * scale)
            this.ctx.arc(x * scale, y * scale, r * scale, 0 - Math.PI / 2, Math.PI * 2 * (1 - this.blink_coldtime / 5) - Math.PI / 2, false)
            this.ctx.lineTo(x * scale, y * scale)

            this.ctx.fillStyle = 'rgba(0,0,255,0.6)'
            this.ctx.fill()
        }

    }

    on_destroy() {
        if (this.role === 'me')
            this.playground.state = 'over'
        for (let i = 0; i < this.playground.players.length; i ++ ) {
            if (this.playground.players[i] === this) {
                this.playground.players.splice(i, 1);
                break
            }
        }
    }
}
